#include "pl011.h"
#include "astralapi.h"

static int rx_irq_handle(object obj)
{
    AstralDevice dev = CAST_AS(AstralDevice, obj);
    ack_receive_int(dev->vbase);
    return 0;
}

int pl011_read(AstralDevice dev, char *buff, int buff_size, int *bytes_read)
{
    int i = 0;
    char c = '\0';
    AstralDevice d = CAST_AS(AstralDevice, dev);
    PL011 model = CAST_AS(PL011, d->vbase);

    while (is_rx_empty(model))
    {
    }
    c = model->UART_DR & 0xff;
    *(buff + i) = c;
    i++;

    *(buff + i) = '\0';
    *bytes_read = i;
    return 0;
}

int pl011_write(AstralDevice dev, const char *buff, int buff_size, int *bytes_write)
{
    int i = 0;
    AstralDevice d = CAST_AS(AstralDevice, dev);
    PL011 model = CAST_AS(PL011, d->vbase);
    while(*buff)
    {
        while (is_tx_full(model))
        {
        }
        model->UART_DR = *buff;
        buff++;
        i++;
    }
    *bytes_write = i;
    return 0;
}

int pl011_open(AstralDevice dev, object arg)
{
    AstralDevice d = CAST_AS(AstralDevice, dev);
    PL011 model = CAST_AS(PL011, d->vbase);
    enable_rx_interrupt(model);
    register_int(d->irq, 0x0, rx_irq_handle,
                 CAST_AS(object, dev), "uart rx irq handler");
    model->UART_CR |= 1;
    return 0;
}

int pl011_close(AstralDevice dev, object arg)
{
    AstralDevice d = CAST_AS(AstralDevice, dev);
    PL011 model = CAST_AS(PL011, d->vbase);

    model->UART_CR &= 0;
    return 0;
}

int pl011_control(AstralDevice dev, int cmd, int arg)
{
    return 0;
}


static struct AstralDriver pl011_driver = {
    .dwrite = pl011_write,
    .dread = pl011_read,
    .dopen = pl011_open,
    .dclose = pl011_close,
    .description = "pl011 driver"};

static void pl011_register(AstralDevice arg)
{
    boolean status = register_driver(MIDv4(96, 1, 0, 1), &pl011_driver);
    kprint("register for %s done, status %d\n",
           pl011_driver.description,
           status);
}

STATIC_REGISTER_DRIVER(pl011_register)

